package dmir.reaction.publico.graph.gephi;

import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;

import org.apache.commons.cli.CommandLine;
import org.gephi.data.attributes.api.AttributeColumn;
import org.gephi.data.attributes.api.AttributeController;
import org.gephi.data.attributes.api.AttributeModel;
import org.gephi.graph.api.Edge;
import org.gephi.graph.api.GraphController;
import org.gephi.graph.api.GraphModel;
import org.gephi.graph.api.Node;
import org.gephi.graph.api.UndirectedGraph;
import org.gephi.io.importer.api.Container;
import org.gephi.io.importer.api.ImportController;
import org.gephi.io.processor.plugin.DefaultProcessor;
import org.gephi.project.api.ProjectController;
import org.gephi.project.api.Workspace;
import org.gephi.statistics.plugin.ClusteringCoefficient;
import org.gephi.statistics.plugin.Degree;
import org.gephi.statistics.plugin.GraphDistance;
import org.openide.util.Lookup;

public class Characterization {

	static Workspace workspace;
	static ImportController importController;
	static GraphModel graphModel;
	static AttributeModel attributeModel;
		
	static File[] graphFiles;
	
	public static void loadGraphs(String directory) {						
		File folder = new File(directory); 
		graphFiles = folder.listFiles();
		Arrays.sort(graphFiles, new Comparator() {
	        @Override
	        public int compare(Object f1, Object f2) {
	          return ((File) f1).getName().compareTo(((File) f2).getName());
	        }
	      });
	}
	
	public static void start(CommandLine line) {
	    //Init a project - and therefore a workspace
	    ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
	    pc.newProject();
	    
	    //Get controllers and models
		Workspace workspace = pc.getCurrentWorkspace();
		ImportController importController = Lookup.getDefault().lookup(ImportController.class);
		GraphModel graphModel = Lookup.getDefault().lookup(GraphController.class).getModel();
		AttributeModel attributeModel = Lookup.getDefault().lookup(AttributeController.class).getModel();
		
		//Import file
	    Container container;
	    try {
	        container = importController.importFile(new File(line.getOptionValue("inputgraph")));
	    } catch (Exception ex) {
	        ex.printStackTrace();
	        return;
	    }

	    //Append imported data to GraphAPI
	    importController.process(container, new DefaultProcessor(), workspace);
	    
	    final UndirectedGraph graph = graphModel.getUndirectedGraph();
	    
	    Comparator<Node> topDegreeComparator = new Comparator<Node>(){
			@Override
			public int compare(Node arg0, Node arg1) {
				
				int degree0 = graph.getDegree(arg0);
				int degree1 = graph.getDegree(arg1);
				
				if (degree0 == degree1)
					return 0;
				return degree0 < degree1 ? 1 : -1;
			}
	    };
	    Comparator<Node> topFreqComparator = new Comparator<Node>() {
			
	    	AttributeModel attributeModel = Lookup.getDefault().lookup(AttributeController.class).getModel();
	    	
			@Override
			public int compare(Node arg0, Node arg1) {
								
				AttributeColumn freq = attributeModel.getNodeTable().getColumn("freq");				
								
				int freq0 = (Integer) arg0.getNodeData().getAttributes().getValue(freq.getIndex());
				int freq1 = (Integer) arg1.getNodeData().getAttributes().getValue(freq.getIndex());
				
				if (freq0 == freq1)
					return 0;
				return freq0 < freq1 ? 1 : -1;
			}
		};

		System.out.print(line.getOptionValue("inputgraph").split(".graphml")[0] + '\t');
		
		LinkedList<Node> nodesListDegree = top(graphModel,topDegreeComparator,false);		
		LinkedList<Node> nodesListFreq = top(graphModel,topFreqComparator,true);
		LinkedList<Edge> edgesList = topEdges(graph);
		
		/*
		System.out.print("Edges: " + graph.getEdgeCount() + '\t');		
		System.out.print("Nodes: " + graph.getNodeCount() + '\t');
		*/
		
		System.out.print(String.valueOf(graph.getEdgeCount()) + '\t');		
		System.out.print(String.valueOf(graph.getNodeCount()) + '\t');
		
		
		//System.out.print("Max Degree: ");
		for (Node n : nodesListDegree) {
	    	System.out.print(String.valueOf(graphModel.getUndirectedGraph().getDegree(n)) + '\t');
	    	break;
	    }
	    
	    AttributeColumn freq = attributeModel.getNodeTable().getColumn("freq");
	    	    
	    for (Node n : nodesListFreq) {
	    	/*
	    	System.out.print("Max Freq entity: " + n.getAttributes().getValue("ename").toString() + '\t');
	    	System.out.print("Max Freq value: " + n.getNodeData().getAttributes().getValue(freq.getIndex()) + '\t');
	    	*/
	    	System.out.print(n.getAttributes().getValue("ename").toString());
	    	System.out.print("\t" + n.getNodeData().getAttributes().getValue(freq.getIndex()) + '\t');
	    	break;
	    }
	    
	    //System.out.print("Max Edge Weight: ");
	    for (Edge e : edgesList) {
	    	System.out.print(String.valueOf(e.getWeight()) + '\t'); 
	    	break;
	    }
	    
	    /* Average Degree */    
	    Degree d = new Degree();
	    d.execute(graphModel, attributeModel);
	    //System.out.print("Average Degree: " + String.valueOf(d.getAverageDegree()) + '\t');
	    System.out.print(String.valueOf(d.getAverageDegree()) + '\t');
	    
	    /* Clustering Coefficient */    
	    ClusteringCoefficient c = new ClusteringCoefficient();
	    c.execute(graphModel, attributeModel);
	    //System.out.print("Average Cluster Coefficient: " + String.valueOf(c.getAverageClusteringCoefficient()) + '\t');
	    System.out.print(String.valueOf(c.getAverageClusteringCoefficient()) + '\t');
	    
	    /* Average Path Length */    
	    GraphDistance gd = new GraphDistance();
	    gd.execute(graphModel, attributeModel);
	    //System.out.print("Average Path Length: " + String.valueOf(gd.getPathLength()) + '\t');
	    System.out.print(String.valueOf(gd.getPathLength()) + '\t');
	}
		
	public static LinkedList<Edge> topEdges(UndirectedGraph graph) {
		
		LinkedList<Edge> edgeList = new LinkedList<Edge>();

		float acc = 0;
	    for (Edge edge : graph.getEdges()) {
	    	edgeList.add(edge);
	    	acc += edge.getWeight();
		}
	    
	    Collections.sort(edgeList, new Comparator<Edge>() {

			@Override
			public int compare(Edge e0, Edge e1) {
				if (e0.getWeight() == e1.getWeight())
					return 0;
				return e0.getWeight() < e1.getWeight() ? 1 : -1;
			}
		});
	    
	    //System.out.print("Avg Edge Weight: " + acc / (float) edgeList.size() + '\t');
	    System.out.print( "\t" + String.valueOf(acc / (float) edgeList.size()) + "\t");
	    
	    return edgeList;
		
	}
	
	public static LinkedList<Node> top(GraphModel graphModel, Comparator comp, boolean frequency) {
		
	    final UndirectedGraph graph = graphModel.getUndirectedGraph();
	    AttributeModel attributeModel = Lookup.getDefault().lookup(AttributeController.class).getModel();
	    AttributeColumn freq = attributeModel.getNodeTable().getColumn("freq");
	    
	    LinkedList<Node> nodesList = new LinkedList<Node>();	    
	    int acc = 0;
	    
	    for (Node n : graph.getNodes()) {
	    	nodesList.add(n);
	    	acc += (Integer) n.getNodeData().getAttributes().getValue(freq.getIndex());
	    }
	    
	    if (frequency) {
	    	//System.out.print("Avg. Frequency: " + acc / (float) nodesList.size() + '\t');
	    	System.out.print( String.valueOf(acc / (float) nodesList.size()));
	    }
	    
	    Collections.sort(nodesList, comp);	    
	    
	    return nodesList;	    
	}
	
	public static void metrics(GraphModel graphModel, AttributeModel attributeModel) {
		
		GraphDistance distance = new GraphDistance();
		distance.execute(graphModel, attributeModel);
		
		//Get Centrality column created
		AttributeColumn col = attributeModel.getNodeTable().getColumn(GraphDistance.BETWEENNESS);
		AttributeColumn degree = attributeModel.getNodeTable().getColumn(Degree.DEGREE);		
		AttributeColumn freq = attributeModel.getNodeTable().getColumn("freq");
		
		final UndirectedGraph graph = graphModel.getUndirectedGraph();
		
		//Iterate over values
		for (Node n : graph.getNodes()) {   
			Double centrality = (Double)n.getNodeData().getAttributes().getValue(col.getIndex());			
			int d = (Integer) n.getNodeData().getAttributes().getValue(degree.getIndex());
			int f = (Integer) n.getNodeData().getAttributes().getValue(freq.getIndex());
			
						
			System.out.println(n.getAttributes().getValue("ename") + "\t" + centrality + "\t" + d + "\t" + f);
		}		
	}
	
}